package com.devops.admin.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.devops.admin.mapper.DOSResourceMapper;
import com.devops.admin.mapper.DOSResourceProjectRelationMapper;
import com.devops.admin.model.DOSResource;
import com.devops.admin.model.DOSResourceProjectRelation;
import com.devops.admin.service.DOSResourceProjectRelationService;
import com.devops.admin.service.DOSResourceService;
import com.devops.admin.util.Assert;
import com.devops.shiro.vm.BaseUserVM;
import org.apache.shiro.SecurityUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @ClassName DOSResourceProjectRelationServiceImpl
 * @Description TODO
 * @Author hepingguo
 * @Date 2022/6/8 11:25
 * @Version 1.0
 **/
@Service
public class DOSResourceProjectRelationServiceImpl extends ServiceImpl<DOSResourceProjectRelationMapper, DOSResourceProjectRelation> implements DOSResourceProjectRelationService {

    @Autowired
    private DOSResourceMapper dosResourceMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean bindRelation(Integer resourceId, List<Integer> projectIds) {
        BaseUserVM user = (BaseUserVM) SecurityUtils.getSubject().getPrincipal();
        Assert.isTrue(null!=user,"该用户未认证");
        //查询数据库中的信息
        LambdaQueryWrapper<DOSResourceProjectRelation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DOSResourceProjectRelation::getResourceId,resourceId);
        if (CollectionUtil.isEmpty(projectIds)){
            return this.remove(queryWrapper);
        }
        List<Integer> distinctProjectIds = projectIds.stream().distinct().collect(Collectors.toList());
        List<DOSResourceProjectRelation> resourceProjectRelations = baseMapper.selectList(queryWrapper);
        //管理员需要取差集，实现一次操作的绑定和解绑
        if (CollectionUtil.isNotEmpty(resourceProjectRelations)) {
            List<Integer> resourceProjectIds = resourceProjectRelations.stream().map(DOSResourceProjectRelation::getProjectId).collect(Collectors.toList());
            //求projectIds相对于resourceProjectIds的差集
            List<Integer> newProjectIds = distinctProjectIds.stream().filter(t -> !resourceProjectIds.contains(t)).collect(Collectors.toList());
            //求projectIds相对于resourceProjectIds的差集
            List<Integer> oldProjectIds = resourceProjectIds.stream().filter(r -> !distinctProjectIds.contains(r)).collect(Collectors.toList());

            if (CollectionUtil.isNotEmpty(oldProjectIds)) {
                queryWrapper.in(DOSResourceProjectRelation::getProjectId, oldProjectIds);
                //解绑资源与项目
                this.remove(queryWrapper);
            }
            if (CollectionUtil.isNotEmpty(newProjectIds)) {
                //封装资源和项目关系的集合
                List<DOSResourceProjectRelation> relations = getRelations(resourceId, newProjectIds);
                //绑定资源和项目
                return this.saveBatch(relations);
            } else{
                return true;
            }
        } else{
            //封装资源和项目关系的集合
            List<DOSResourceProjectRelation> relations = getRelations(resourceId, distinctProjectIds);
            return this.saveBatch(relations);
        }
    }

    @Override
    public boolean noBindRelation(Integer resourceId, Integer projectId) {
        BaseUserVM user = (BaseUserVM) SecurityUtils.getSubject().getPrincipal();
        Assert.isTrue(null!=user,"该用户未认证");
        Assert.isTrue(null != resourceId && resourceId.intValue() > 0,"资源id不能为空");
        Assert.isTrue(null != projectId && projectId.intValue() > 0,"项目id不能为空");

        LambdaQueryWrapper<DOSResourceProjectRelation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DOSResourceProjectRelation::getResourceId,resourceId)
                .eq(DOSResourceProjectRelation::getProjectId,projectId);

        return this.remove(queryWrapper);
    }

    @Override
    public boolean bindRelations(Integer resourceId, List<Integer> projectIds) {
        BaseUserVM user = (BaseUserVM) SecurityUtils.getSubject().getPrincipal();
        Assert.isTrue(null!=user,"该用户未认证");
        Assert.isTrue(null != resourceId && resourceId.intValue() > 0,"资源id不能为空");
        Assert.isTrue(CollectionUtil.isNotEmpty(projectIds),"项目id不能为空");
        LambdaQueryWrapper<DOSResourceProjectRelation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DOSResourceProjectRelation::getResourceId,resourceId);
        List<DOSResourceProjectRelation> resourceProjectRelations = baseMapper.selectList(queryWrapper);
        //管理员需要取差集，实现一次操作的绑定和解绑
        if (CollectionUtil.isNotEmpty(resourceProjectRelations) && user.getAdminRole()) {
            List<Integer> resourceProjectIds = resourceProjectRelations.stream().map(DOSResourceProjectRelation::getProjectId).collect(Collectors.toList());
            //求projectIds相对于resourceProjectIds的差集
            List<Integer> newProjectIds = projectIds.stream().filter(t -> !resourceProjectIds.contains(t)).collect(Collectors.toList());

            //封装资源和项目关系的集合
            List<DOSResourceProjectRelation> relations = getRelations(resourceId, newProjectIds);
            if (CollectionUtil.isNotEmpty(relations)) {
                //绑定资源和项目
                return this.saveBatch(relations);
            } else{
                return true;
            }
        } else{
            if (!user.getAdminRole()){
                Assert.isTrue(projectIds.size() == 1,"非管理员身份无法批量绑定，请选择一个进行绑定");
                queryWrapper.eq(DOSResourceProjectRelation::getProjectId,projectIds.get(0));
                long count = this.count(queryWrapper);
                Assert.isTrue(count < 1,"无法重复绑定");
            }
            //封装资源和项目关系的集合
            List<DOSResourceProjectRelation> relations = getRelations(resourceId, projectIds);
            return this.saveBatch(relations);
        }
    }

    @Override
    public boolean noBindRelations(Integer resourceId, List<Integer> projectIds) {
        BaseUserVM user = (BaseUserVM) SecurityUtils.getSubject().getPrincipal();
        Assert.isTrue(null!=user,"该用户未认证");
        Assert.isTrue(null != resourceId && resourceId.intValue() > 0,"资源id不能为空");
        Assert.isTrue(CollectionUtil.isNotEmpty(projectIds),"项目id不能为空");
        if (!user.getAdminRole()){
            Assert.isTrue(projectIds.size() == 1,"非管理员身份无法批量绑定，请选择一个进行绑定");
        }
        LambdaQueryWrapper<DOSResourceProjectRelation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DOSResourceProjectRelation::getResourceId,resourceId)
                .in(DOSResourceProjectRelation::getProjectId,projectIds);

        return this.remove(queryWrapper);
    }

    @Override
    public boolean bindResourceProject(List<Integer> resourceIds, Integer projectId, Integer type) {
        Assert.isTrue(projectId != null && projectId.intValue() > 0,"项目id不能为空");
        LambdaQueryWrapper<DOSResourceProjectRelation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DOSResourceProjectRelation::getProjectId,projectId);
        LambdaQueryWrapper<DOSResource> resourceLambdaQueryWrapper = new LambdaQueryWrapper<>();
        resourceLambdaQueryWrapper.eq(DOSResource::getType,type);
        List<DOSResource> dosResources = dosResourceMapper.selectList(resourceLambdaQueryWrapper);
        if (CollectionUtil.isEmpty(resourceIds)){
            if (CollectionUtil.isNotEmpty(dosResources)){
                List<Integer> oldResourceIds = dosResources.stream().map(DOSResource::getId).collect(Collectors.toList());
                queryWrapper.in(DOSResourceProjectRelation::getResourceId,oldResourceIds);
                return this.remove(queryWrapper);
            } else{
                return this.remove(queryWrapper);
            }
        }

        List<Integer> distinctResourceIds = resourceIds.stream().distinct().collect(Collectors.toList());
        List<DOSResourceProjectRelation> resourceProjectRelations = baseMapper.selectList(queryWrapper);
        if (CollectionUtil.isNotEmpty(resourceProjectRelations)){
            List<Integer> databaseResourceIds = resourceProjectRelations.stream().map(DOSResourceProjectRelation::getResourceId).collect(Collectors.toList());
            //求resourceIds相对于databaseResourceIds的差集
            List<Integer> newResourceIds = distinctResourceIds.stream().filter(t -> !databaseResourceIds.contains(t)).collect(Collectors.toList());
            //求databaseResourceIds相对于resourceIds的差集
            List<Integer> oldResourceIds = databaseResourceIds.stream().filter(t -> !distinctResourceIds.contains(t)).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(oldResourceIds)) {
                if (CollectionUtil.isNotEmpty(dosResources)){
                    List<Integer> resourceIdList = dosResources.stream().map(DOSResource::getId).collect(Collectors.toList());
                    List<Integer> deleteResourceIds = oldResourceIds.stream().filter(t -> resourceIdList.contains(t)).collect(Collectors.toList());
                    if (CollectionUtil.isNotEmpty(deleteResourceIds)) {
                        queryWrapper.in(DOSResourceProjectRelation::getResourceId, deleteResourceIds);
                        this.remove(queryWrapper);
                    }
                } else{
                    queryWrapper.in(DOSResourceProjectRelation::getResourceId, oldResourceIds);
                    //解绑资源与项目
                    this.remove(queryWrapper);
                }
            }
            if (CollectionUtil.isNotEmpty(newResourceIds)) {
                List<DOSResourceProjectRelation> relations = getRelations(newResourceIds, projectId);
                //绑定资源和项目
                return this.saveBatch(relations);
            } else{
                return true;
            }
        } else{
            List<DOSResourceProjectRelation> relations = getRelations(distinctResourceIds, projectId);

            //绑定资源和项目
            return this.saveBatch(relations);
        }

    }

    /**
     * @Author heyabo
     * @Description 封装资源和项目关系的集合
     * @Date 09:40 2022/6/9
     * @Param [resourceId, projectIds]
     * @return java.util.List<com.devops.admin.model.DOSResourceProjectRelation>
     **/
    @NotNull
    private List<DOSResourceProjectRelation> getRelations(Integer resourceId, List<Integer> projectIds) {
        List<DOSResourceProjectRelation> relations = new ArrayList<>();
        projectIds.forEach(projectId->{
            DOSResourceProjectRelation relation = new DOSResourceProjectRelation();
            relation.setResourceId(resourceId);
            relation.setProjectId(projectId);
            relations.add(relation);
        });
        return relations;
    }

    /**
     * @Author heyabo
     * @Description 封装项目和资源关系的集合
     * @Date 09:40 2022/6/9
     * @Param [resourceId, projectIds]
     * @return java.util.List<com.devops.admin.model.DOSResourceProjectRelation>
     **/
    @NotNull
    private List<DOSResourceProjectRelation> getRelations(List<Integer> resourceIds, Integer projectId) {
        List<DOSResourceProjectRelation> relations = new ArrayList<>();
        resourceIds.forEach(resourceId->{
            DOSResourceProjectRelation relation = new DOSResourceProjectRelation();
            relation.setResourceId(resourceId);
            relation.setProjectId(projectId);
            relations.add(relation);
        });
        return relations;
    }
}
